/***************************************************************
 *
 * (c) 2008 Markus Dittrich 
 *
 * This program is free software; you can redistribute it 
 * and/or modify it under the terms of the GNU General Public 
 * License Version 3 as published by the Free Software Foundation. 
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License Version 3 for more details.
 *
 * You should have received a copy of the GNU General Public 
 * License along with this program; if not, write to the Free 
 * Software Foundation, Inc., 59 Temple Place - Suite 330, 
 * Boston, MA 02111-1307, USA.
 *
 ****************************************************************/

/* STL includes */
#include <iostream>

/* Qt includes */
#include <QAction>
#include <QHBoxLayout>
#include <QListWidgetItem>
#include <QMenu>
#include <QMessageBox>
#include <QMouseEvent>

/* local includes */
#include "basic_definitions.h"
#include "data_selector_widget.h"
#include "utilities.h"



/*****************************************************************
 *
 *
 * class DataNameWidget
 *
 *
 ****************************************************************/

/*****************************************************************
 *
 * public member functions 
 *
 ****************************************************************/
//---------------------------------------------------------------
// constructor
//---------------------------------------------------------------
DataNameWidget::DataNameWidget(QWidget* theParent)
  :
    QListWidget(theParent),
    parent_(theParent)
{
  status_ = SUCCESSFULLY_CONSTRUCTED;
}


//---------------------------------------------------------------
// main initialization function
//---------------------------------------------------------------
bool DataNameWidget::Init()
{
  if ( status_ != SUCCESSFULLY_CONSTRUCTED )
  {
    return false;
  }

  connect(this,SIGNAL(right_mouse_click(QMouseEvent*)),parent_,
    SLOT(show_data_selector_actions_(QMouseEvent*)));
  connect(this,SIGNAL(right_mouse_double_click(QMouseEvent*)),parent_,
    SLOT(toggle_visibility_(QMouseEvent*)));

  return true;
}

 
  
/*****************************************************************
 *
 * protected member functions 
 *
 ****************************************************************/
//---------------------------------------------------------------
// overload mouse press events
//---------------------------------------------------------------
void DataNameWidget::mousePressEvent(QMouseEvent* anEvent)
{
  if ( anEvent->button() == Qt::RightButton )
  {
    emit right_mouse_click(anEvent);
  }
  else
  {
    QListWidget::mousePressEvent(anEvent);
  }
}


//---------------------------------------------------------------
// overload mouse double click events
//---------------------------------------------------------------
void DataNameWidget::mouseDoubleClickEvent(QMouseEvent* anEvent)
{
  if ( anEvent->button() == Qt::LeftButton )
  {
    emit right_mouse_double_click(anEvent);
  }
  else
  {
    QListWidget::mouseDoubleClickEvent(anEvent);
  }
}



/*****************************************************************
 *
 *
 * class DataSelectorWidget
 *
 *
 ****************************************************************/

/*****************************************************************
 *
 * public member functions 
 *
 ****************************************************************/
//---------------------------------------------------------------
// constructor
//---------------------------------------------------------------
DataSelectorWidget::DataSelectorWidget(QWidget* theParent)
  :
    QWidget(theParent),
    parent_(theParent)
{
  status_ = SUCCESSFULLY_CONSTRUCTED;
}


//---------------------------------------------------------------
// main initialization function
//---------------------------------------------------------------
bool DataSelectorWidget::Init()
{
  if ( status_ != SUCCESSFULLY_CONSTRUCTED)
  {
    return false;
  }

  /* generate layout */
  generate_data_list_();

  /* populate main layout */
  QHBoxLayout* mainLayout = new QHBoxLayout;
  mainLayout->addWidget(dataNameList_);
  setLayout(mainLayout);

  /* connections to MainWindow */
  connect(this,SIGNAL(hide_items(bool, QList<QString>)),
      parent_, SLOT(hide_data_items(bool, QList<QString>)));
  connect(this,SIGNAL(delete_items(QList<QString>)),
      parent_, SLOT(delete_data_items(QList<QString>)));
  connect(dataNameList_,SIGNAL(currentRowChanged(int)),this,
      SIGNAL(selected_data_item_changed(int)));
  connect(this,SIGNAL(create_histogram()),parent_,
      SLOT(show_histogram_selector()));

  return true;
}


//----------------------------------------------------------------
// add a new data set to widget
// NOTE: we display the filename (not the full path) inside the
// widget, but keep the full name in a QVariant so we can
// pass it on to the MainWindow later on
//----------------------------------------------------------------
void DataSelectorWidget::add_data_item(const QString& dataName,
    const QColor& labelColor)
{
  QString widgetString = generate_widget_string_(dataName, false);
  QListWidgetItem* newItem = new QListWidgetItem(widgetString);
  newItem->setData(FULL_NAME,QVariant(dataName));
  newItem->setData(HIDDEN_FLAG,QVariant(false));
  newItem->setForeground(QBrush(labelColor));

  dataNameList_->addItem(newItem);
  dataNameList_->clearSelection();
  dataNameList_->setCurrentItem(newItem);
}


//---------------------------------------------------------------
// return the names of all selected items
//---------------------------------------------------------------
QList<QString> DataSelectorWidget::get_selected_item_names() const
{
  QList<QString> selectedDataNames;
  QList<QListWidgetItem*> selectedItemsList = 
    dataNameList_->selectedItems();
  FOREACH(const QListWidgetItem* dataItem, selectedItemsList)
  {
    /* NOTE: we need to pass full name to main Window
     * which is stored in QVariant */
    QString fullName = dataItem->data(FULL_NAME).toString();
    selectedDataNames.append(fullName);
  }

  return selectedDataNames;
}


//---------------------------------------------------------------
// return the number of selected items in the selector widget
//---------------------------------------------------------------
int DataSelectorWidget::num_selected_items() const
{
  return dataNameList_->selectedItems().size();
}



/*****************************************************************
 *
 * public slots 
 *
 ****************************************************************/
//----------------------------------------------------------------
// open popup window with possible actions for the current
// set of selected data items
//----------------------------------------------------------------
void DataSelectorWidget::show_data_selector_actions_(
    QMouseEvent* anEvent)
{
  QMenu* selector = new QMenu;
  QAction* hideAction = new QAction(tr("hide"),selector);
  QAction* showAction = new QAction(tr("show"),selector);
  QAction* histogramAction = 
    new QAction(tr("generate histogram"),selector);
  QAction* deleteAction = new QAction(tr("delete"),selector);
  selector->addAction(hideAction);
  selector->addAction(showAction);
  selector->addSeparator();
  selector->addAction(histogramAction);
  selector->addSeparator();
  selector->addAction(deleteAction);
  QAction* result = selector->exec(anEvent->globalPos());

  if ( result == hideAction )
  {
    hide_data_(true);
  }
  else if ( result == showAction )
  {
    hide_data_(false);
  }
  else if ( result == histogramAction )
  {
    emit create_histogram();
  }
  else if ( result == deleteAction )
  {
    delete_data_();
  }

  /* done with the selector */
  delete selector;
}


//----------------------------------------------------------------
// a double click toggles the visibility of all selected 
// data items
//----------------------------------------------------------------
void DataSelectorWidget::toggle_visibility_(QMouseEvent* anEvent)
{
  /* accept the event to silence gcc */
  anEvent->accept();

  QList<QString> hiddenDataNames;
  QList<QString> visibleDataNames;
  QList<QListWidgetItem*> toggledItemsList = 
    dataNameList_->selectedItems();
   
  FOREACH(QListWidgetItem* hiddenItem, toggledItemsList)
  {
    /* NOTE: we need to pass full name to main Window
     * which is stored in QVariant */
    QString fullName = hiddenItem->data(FULL_NAME).toString();
    bool visible = hiddenItem->data(HIDDEN_FLAG).toBool();

    /* if data is already hidden we make it visible;
     * otherwise we hide it */
    if ( visible )
    {
      hiddenDataNames.append(fullName);
    }
    else
    {
      visibleDataNames.append(fullName);
    }

    /* adjust properties and display string */
    QString newWidgetString = 
      generate_widget_string_(fullName, !visible);
    hiddenItem->setText(newWidgetString);
    hiddenItem->setData(HIDDEN_FLAG,QVariant(!visible));
  }

  emit hide_items(true, visibleDataNames);
  emit hide_items(false, hiddenDataNames);
}


//----------------------------------------------------------------
// slot changing the color of a particular label
//----------------------------------------------------------------
void DataSelectorWidget::change_label_color(const QString& labelName,
  const QColor& colorName)
{
  /* find QListWidgetItem corresponding to labelName */
  int numElements = dataNameList_->count();
  for ( int counter = 0; counter < numElements; ++counter )
  {
    QListWidgetItem* item = dataNameList_->item(counter);
    QString itemName = item->data(FULL_NAME).toString();

    if ( itemName == labelName )
    {
      item->setForeground(QBrush(colorName));
    }
  }
}


/*****************************************************************
 *
 * private member functions
 *
 ****************************************************************/
//----------------------------------------------------------------
// gather the names of all slots to be hidden and pass them 
// on to the main window 
//----------------------------------------------------------------
void DataSelectorWidget::hide_data_(bool aState)
{
  QList<QString> hiddenDataNames;
  QList<QListWidgetItem*> hiddenItemsList = 
    dataNameList_->selectedItems();
  FOREACH(QListWidgetItem* hiddenItem, hiddenItemsList)
  {
    /* NOTE: we need to pass full name to main Window
     * which is stored in QVariant */
    QString fullName = hiddenItem->data(FULL_NAME).toString();
    hiddenDataNames.append(fullName);

    /* adjust properties and display string */
    QString newWidgetString = 
      generate_widget_string_(fullName, aState);
    hiddenItem->setText(newWidgetString);
    hiddenItem->setData(HIDDEN_FLAG,QVariant(aState));
  }

  emit hide_items(aState, hiddenDataNames);
}


//----------------------------------------------------------------
// gather the names of all slots to be removed, delete the
// QListWidgetItems and pass the names on to the 
// main window for final cleanup.
// Make sure to delete the items in dataPropertyList as well to
// keep them in sync
//----------------------------------------------------------------
void DataSelectorWidget::delete_data_()
{
  /* ask for confirmation */
  QMessageBox::StandardButton answer = QMessageBox::warning(
      this, tr("Warning"), 
      tr("Are you sure you want to delete selected data sets"),
      QMessageBox::Yes | QMessageBox::No);

  if ( answer != QMessageBox::Yes )
  {
    return;
  }

  QList<QString> deadDataNames;
  QList<QListWidgetItem*> deadItemsList = 
    dataNameList_->selectedItems();
  FOREACH(const QListWidgetItem* deadItem, deadItemsList)
  {
    /* NOTE: we need to pass full name to main Window
     * which is stored in QVariant */
    QString fullName = deadItem->data(FULL_NAME).toString();
    deadDataNames.append(fullName);
    int dataRow = dataNameList_->row(deadItem);
    delete dataNameList_->takeItem(dataRow);
  }

  emit delete_items(deadDataNames);
}


//----------------------------------------------------------------
// generate the data entry to be displayed in the widget;
// it contains status information via single letter flags:
//     H = hidden
//----------------------------------------------------------------
QString DataSelectorWidget::generate_widget_string_(
    const QString& rawName, bool hiddenFlag) const
{
  QString hiddenTag("V  ");
  if ( hiddenFlag ) 
  {
    hiddenTag = QString("H  ");
  }

  return hiddenTag + strip_path(rawName);
}


  
//----------------------------------------------------------------
// generate the data name QListWidget
//----------------------------------------------------------------
void DataSelectorWidget::generate_data_list_()
{
  dataNameList_ = new DataNameWidget(this);
  dataNameList_->Init();
  dataNameList_->setSortingEnabled(false);
  dataNameList_->setSelectionMode(
      QAbstractItemView::ExtendedSelection);
}
